<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../assets/css/base.css">
</head>
<body>
    <div id="app">
        <p v-text="msg"></p>
        <hr>
        <p v-text="info"></p>
        <hr>
        <p v-text="msg"></p>
        <hr>
        <p v-text="info"></p>
        <hr>
        <p v-text="msg"></p>
        <hr>
        <p v-text="info"></p>
        <br>
        <input type="button" value="修改msg" v-on="setMsg">
        <input type="button" value="修改info" v-on="setInfo">

    </div>
    
    <script>
        function mount(_data={},_methods,el){
            // _data 工厂函数创建的数据仓库对象
            console.log(_data)
            // _methods 方法仓库对象
            console.log(_methods)
            // 实例对应的容器选择器
            console.log(el)

            // 响应式核心代码 ==>
            // 定义一个vue实例对象
            let vm = {};
            // 获取根容器
            let root = document.querySelector(el);

            // 循环数据
            for (let propName in _data) {
                let tempEl = "[v-text='"+propName+"']";
                let propNameToDoms = root.querySelectorAll(tempEl)
                // 将数据完成劫持,并存储于vue根实例上
                Object.defineProperty(vm,propName,{
                    get(){
                        return _data[propName]
                    },
                    set(nv){
                        _data[propName] = nv;

                        propNameToDoms.forEach(element => {
                            element.textContent = _data[propName]
                        });
                    }
                })
                propNameToDoms.forEach(element => {
                    element.textContent = _data[propName]
                });
            }

            // 循环方法
            for (let funName in _methods) {
                // 将方法存储于vue的根实例上
                vm[funName] = _methods[funName].bind(vm);
                let eventDoms = root.querySelectorAll(`[v-on='${funName}']`)
                // console.log(eventDoms)
                eventDoms.forEach(element => {
                    element.addEventListener("click",function(){
                        vm[funName]();
                    })
                });
            }


            // <== 响应式核心代码
            return vm;
        }
        function createApp(options={}){
            // 调用工厂函数，返回需要使用的数据仓库对象
            let _data = options.data();
            let _methods = options.methods;

            return {
                _data,
                _methods,
                // 通过bind方法将mount前两个参数设置为 数据仓库和方法仓库
                mount:mount.bind(null,_data,_methods)
            }
        }

        const app = createApp({
            data:function(){
                return {
                   msg:"msg消息",
                   info:"info消息"
                }
            },
            methods: {
                setMsg:function() {
                    console.log("setMsg")
                    this.msg = Math.random();
                },
                setInfo:function(){
                    console.log("setInfo")
                    this.info = Math.random();
                }
            },
        })
        const vm = app.mount("#app");


        // 1、应用创建  createApp
        // 2、挂载应用并获取数据配置
        // 3、构建响应式数据（只完成data一层数据劫持）
        // 4、完成劫持变量和页面元素的关联

        // 5、完成方法绑定操作
    </script>
</body>
</html>